/*
 * Copyright (C) 2012 www.amsoft.cn
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ab.image;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.view.View;
import android.widget.ImageView;

import com.ab.cache.AbCacheHeaderParser;
import com.ab.cache.AbCacheResponse;
import com.ab.cache.AbCacheUtil;
import com.ab.cache.AbDiskBaseCache;
import com.ab.cache.AbDiskCache.Entry;
import com.ab.cache.image.AbBitmapResponse;
import com.ab.cache.image.AbImageBaseCache;
import com.ab.global.AbAppConfig;
import com.ab.task.AbTaskItem;
import com.ab.task.AbTaskObjectListener;
import com.ab.task.thread.AbTaskQueue;
import com.ab.util.AbAppUtil;
import com.ab.util.AbFileUtil;
import com.ab.util.AbImageUtil;
import com.ab.util.AbLogUtil;
import com.ab.util.AbStrUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

// TODO: Auto-generated Javadoc

/**
 * © 2012 amsoft.cn
 * 名称：AbImageLoader.java
 * 描述：下载图片并显示的工具类.
 *
 * @author 还如一梦中
 * @version v1.0
 * @date：2011-12-10 上午10:10:53
 */
public class AbImageLoader {

    /**
     * 上下文.
     */
    private Context context = null;

    /**
     * 单例对象.
     */
    private static AbImageLoader imageLoader = null;

    /**
     * 缓存超时时间设置.
     */
    private long cacheMaxAge;

    /**
     * 请求队列.
     */
    private List<AbTaskQueue> taskQueueList;

    /**
     * 图片缓存.
     */
    private AbImageBaseCache memCache;

    /**
     * 磁盘缓存.
     */
    private AbDiskBaseCache diskCache;

    /**
     * 构造图片下载器.
     *
     * @param context the context
     */
    public AbImageLoader(Context context) {
        this.context = context;
        this.cacheMaxAge = AbAppConfig.DISK_CACHE_EXPIRES_TIME;
        this.taskQueueList = new ArrayList<AbTaskQueue>();
        PackageInfo info = AbAppUtil.getPackageInfo(context);
        File cacheDir = null;
        if (!AbFileUtil.isCanUseSD()) {
            cacheDir = new File(context.getCacheDir(), info.packageName);
        } else {
            cacheDir = new File(AbFileUtil.getCacheDownloadDir(context));
        }
        this.diskCache = new AbDiskBaseCache(cacheDir);
        this.memCache = AbImageBaseCache.getInstance();
    }


    /**
     * 获得一个实例.
     *
     * @param context
     * @return
     */
    public static AbImageLoader getInstance(Context context) {
        if (imageLoader == null) {
            imageLoader = new AbImageLoader(context);
        }
        return imageLoader;
    }

    /**
     * 显示这个图片.
     *
     * @param imageView
     * @param url
     * @param desiredWidth
     * @param desiredHeight
     */
    public void display(ImageView imageView, String url, int desiredWidth, int desiredHeight) {
        download(imageView, url, desiredWidth, desiredHeight, new OnImageListener() {

            @Override
            public void onSuccess(ImageView imageView, Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
            }

            @Override
            public void onLoading(ImageView imageView) {

            }

            @Override
            public void onError(ImageView imageView) {

            }

            @Override
            public void onEmpty(ImageView imageView) {

            }
        });
    }

    /**
     * 显示这个图片(按照原图尺寸).
     * ImageView使用android:scaleType="fitXY"属性仍旧可以充满
     *
     * @param imageView
     * @param url
     */
    public void display(ImageView imageView, String url) {
        download(imageView, url, -1, -1, new OnImageListener() {

            @Override
            public void onSuccess(ImageView imageView, Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
            }

            @Override
            public void onLoading(ImageView imageView) {

            }

            @Override
            public void onError(ImageView imageView) {
//                imageView.setVisibility(View.VISIBLE);
//                imageView.setImageBitmap(null);
            }

            @Override
            public void onEmpty(ImageView imageView) {
//                imageView.setVisibility(View.VISIBLE);
//                imageView.setImageBitmap(null);
            }
        });
    }

    /**
     * 显示这个图片.
     *
     * @param imageView
     * @param loadingView
     * @param url
     * @param desiredWidth
     * @param desiredHeight
     */
    public void display(final ImageView imageView, final View loadingView, final String url, final int desiredWidth, final int desiredHeight) {
        download(imageView, url, desiredWidth, desiredHeight, new OnImageListener() {

            public void onSuccess(ImageView imageView, Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
                imageView.setVisibility(View.VISIBLE);
                loadingView.setVisibility(View.GONE);
            }

            @Override
            public void onLoading(ImageView imageView) {
                imageView.setVisibility(View.GONE);
                loadingView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onError(ImageView imageView) {
                loadingView.setVisibility(View.GONE);
                imageView.setVisibility(View.VISIBLE);
                imageView.setImageBitmap(null);
            }

            @Override
            public void onEmpty(ImageView imageView) {
                imageView.setImageBitmap(null);
                loadingView.setVisibility(View.GONE);
                imageView.setVisibility(View.VISIBLE);
            }
        });
    }


    /**
     * 下载这个图片.
     *
     * @param imageView
     * @param url
     * @param desiredWidth
     * @param desiredHeight
     */
    public void download(final ImageView imageView, final String url, final int desiredWidth, final int desiredHeight, final OnImageListener onImageListener) {

        if (AbStrUtil.isEmpty(url)) {
            if (onImageListener != null) {
                onImageListener.onEmpty(imageView);
            }
            return;
        }

        final String cacheKey = memCache.getCacheKey(url, desiredWidth, desiredHeight);
        //先看内存
        Bitmap bitmap = memCache.getBitmap(cacheKey);
        AbLogUtil.i(AbImageLoader.class, "从LRUCache中获取到的图片" + cacheKey + ":" + bitmap);

        if (bitmap != null) {
            if (onImageListener != null) {
                onImageListener.onSuccess(imageView, bitmap);
            }
        } else {

            if (onImageListener != null) {
                onImageListener.onLoading(imageView);
            }

            if (imageView != null) {
                //设置标记,目的解决闪烁问题
                imageView.setTag(url);
            }

            AbTaskItem item = new AbTaskItem();
            item.setListener(new AbTaskObjectListener() {

                @Override
                public <T> void update(T entity) {
                    AbBitmapResponse response = (AbBitmapResponse) entity;
                    if (response == null) {
                        if (onImageListener != null) {
                            onImageListener.onError(imageView);
                        }
                    } else {
                        Bitmap bitmap = response.getBitmap();
                        //要判断这个imageView的url有变化，如果没有变化才set
                        //有变化就取消，解决列表的重复利用View的问题
                        if (bitmap == null) {
                            if (onImageListener != null) {
                                onImageListener.onEmpty(imageView);

                            }
                        } else if (imageView == null || url.equals(imageView.getTag())) {
                            if (onImageListener != null) {
                                onImageListener.onSuccess(imageView, bitmap);
                            }
                        }
                        AbLogUtil.d(AbImageLoader.class, "获取到图片：" + bitmap);
                    }

                }

                @Override
                public AbBitmapResponse getObject() {
                    return getBitmapResponse(url, desiredWidth, desiredHeight);
                }

            });

            add2Queue(item);
        }

    }


    /**
     * 下载这个图片.
     *
     * @param url
     * @param desiredWidth
     * @param desiredHeight
     */
    public void download(final String url, final int desiredWidth, final int desiredHeight, final OnImageListener2 onImageListener) {

        if (AbStrUtil.isEmpty(url)) {
            if (onImageListener != null) {
                onImageListener.onEmpty();
            }
            return;
        }

        final String cacheKey = memCache.getCacheKey(url, desiredWidth, desiredHeight);
        //先看内存
        Bitmap bitmap = memCache.getBitmap(cacheKey);
        AbLogUtil.i(AbImageLoader.class, "从LRUCache中获取到的图片" + cacheKey + ":" + bitmap);

        if (bitmap != null) {
            if (onImageListener != null) {
                onImageListener.onSuccess(bitmap);
            }
        } else {

            if (onImageListener != null) {
                onImageListener.onLoading();
            }

            AbTaskItem item = new AbTaskItem();
            item.setListener(new AbTaskObjectListener() {

                @Override
                public <T> void update(T entity) {
                    AbBitmapResponse response = (AbBitmapResponse) entity;
                    if (response == null) {
                        if (onImageListener != null) {
                            onImageListener.onError();
                        }
                    } else {
                        Bitmap bitmap = response.getBitmap();
                        //要判断这个imageView的url有变化，如果没有变化才set
                        //有变化就取消，解决列表的重复利用View的问题
                        if (bitmap == null) {
                            if (onImageListener != null) {
                                onImageListener.onEmpty();
                            }
                        } else {
                            if (onImageListener != null) {
                                onImageListener.onSuccess(bitmap);
                            }
                        }
                        AbLogUtil.d(AbImageLoader.class, "获取到图片：" + bitmap);
                    }

                }

                @Override
                public AbBitmapResponse getObject() {
                    try {
                        return getBitmapResponse(url, desiredWidth, desiredHeight);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                }

            });

            add2Queue(item);
        }

    }

    /**
     * 获取AbBitmapResponse.
     *
     * @param url
     * @param desiredWidth
     * @param desiredHeight
     * @return
     */
    public AbBitmapResponse getBitmapResponse(String url, int desiredWidth, int desiredHeight) {
        AbBitmapResponse bitmapResponse = null;
        try {
            final String cacheKey = memCache.getCacheKey(url, desiredWidth, desiredHeight);
            Bitmap bitmap = null;
            //看磁盘
            Entry entry = diskCache.get(cacheKey);
            if (entry == null || entry.isExpired()) {
                if (entry == null) {
                    AbLogUtil.i(AbImageLoader.class, "磁盘中没有这个图片");
                } else {
                    if (entry.isExpired()) {
                        AbLogUtil.i(AbImageLoader.class, "磁盘中图片已经过期");
                    }
                }

                AbCacheResponse response = AbCacheUtil.getCacheResponse(url);
                if (response != null) {
                    bitmap = AbImageUtil.getBitmap(response.data, desiredWidth, desiredHeight);
                    if (bitmap != null) {
                        memCache.putBitmap(cacheKey, bitmap);
                        AbLogUtil.i(AbImageLoader.class, "图片缓存成功");
                        diskCache.put(cacheKey, AbCacheHeaderParser.parseCacheHeaders(response, cacheMaxAge));
                    }
                }
            } else {
                //磁盘中有
                byte[] bitmapData = entry.data;
                bitmap = AbImageUtil.getBitmap(bitmapData, desiredWidth, desiredHeight);
                memCache.putBitmap(cacheKey, bitmap);
            }

            bitmapResponse = new AbBitmapResponse(url);
            bitmapResponse.setBitmap(bitmap);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmapResponse;
    }


    /**
     * 设置缓存的最大时间.
     *
     * @return
     */
    public long getCacheMaxAge() {
        return cacheMaxAge;
    }


    /**
     * 获取缓存的最大时间.
     *
     * @param cacheMaxAge
     */
    public void setCacheMaxAge(long cacheMaxAge) {
        this.cacheMaxAge = cacheMaxAge;
    }


    /**
     * 监听器
     */
    public interface OnImageListener {

        /**
         * On Empty.
         *
         * @param imageView
         */
        public void onEmpty(ImageView imageView);

        /**
         * On Loading.
         *
         * @param imageView
         */
        public void onLoading(ImageView imageView);

        /**
         * On Error.
         *
         * @param imageView
         */
        public void onError(ImageView imageView);

        /**
         * On response.
         *
         * @param imageView
         * @param bitmap
         */
        public void onSuccess(ImageView imageView, Bitmap bitmap);
    }

    /**
     * 监听器
     */
    public interface OnImageListener2 {

        /**
         * On Empty.
         *
         * @param imageView
         */
        public void onEmpty();

        /**
         * On Loading.
         *
         * @param imageView
         */
        public void onLoading();

        /**
         * On Error.
         *
         * @param imageView
         */
        public void onError();

        /**
         * On response.
         *
         * @param imageView
         * @param bitmap
         */
        public void onSuccess(Bitmap bitmap);
    }

    /**
     * 增加到最少的队列中.
     *
     * @param item
     */
    private void add2Queue(AbTaskItem item) {
        int minQueueIndex = 0;
        if (taskQueueList.size() == 0) {
            AbTaskQueue queue = AbTaskQueue.newInstance();
            taskQueueList.add(queue);
            queue.execute(item);
        } else {
            int minSize = 0;
            for (int i = 0; i < taskQueueList.size(); i++) {
                AbTaskQueue queue = taskQueueList.get(i);
                int size = queue.getTaskItemListSize();
                if (i == 0) {
                    minSize = size;
                    minQueueIndex = i;
                } else {
                    if (size < minSize) {
                        minSize = size;
                        minQueueIndex = i;
                    }
                }
            }
            if (taskQueueList.size() < 5 && minSize > 2) {
                AbTaskQueue queue = AbTaskQueue.newInstance();
                taskQueueList.add(queue);
                queue.execute(item);
            } else {
                AbTaskQueue minQueue = taskQueueList.get(minQueueIndex);
                minQueue.execute(item);
            }

        }

        for (int i = 0; i < taskQueueList.size(); i++) {
            AbTaskQueue queue = taskQueueList.get(i);
            int size = queue.getTaskItemListSize();
            AbLogUtil.i(AbImageLoader.class, "线程队列[" + i + "]的任务数：" + size);
        }

    }

    /**
     * 释放资源.
     */
    public void cancelAll() {
        for (int i = 0; i < taskQueueList.size(); i++) {
            AbTaskQueue queue = taskQueueList.get(i);
            queue.cancel(true);
        }
        taskQueueList.clear();
    }


    public AbImageBaseCache getMemCache() {
        return memCache;
    }


    public void setMemCache(AbImageBaseCache memCache) {
        this.memCache = memCache;
    }


    public AbDiskBaseCache getDiskCache() {
        return diskCache;
    }


    public void setDiskCache(AbDiskBaseCache diskCache) {
        this.diskCache = diskCache;
    }

}

